﻿namespace ConsoleApplication
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading;
    using EveKillboard.Core;
    using EveKillboard.Core.Services;
    using EveKillboard.Data;
    using EveKillboard.Services.EveKillServices;
    using Properties;
    using EveKillboard.Core.Interfaces;
    using System.Reflection;
    using System.Configuration;

    class Program
    {
        static readonly TraceSource Trace = new TraceSource("KillmailsGrabber");

        static void Main(string[] args)
        {
            var api = new EveApiServicesProvider();

            int initErrorsCount = 0;
            const int MAX_ERRORS = 3;

            while (!Console.KeyAvailable)
            {
                Console.Clear();

                IDataAccessProvider dap = null;
                try
                {
                    Trace.TraceEvent(TraceEventType.Information, "Initializing DataAccessProvider");

                    dap = new DataAccessProvider();

                    Trace.TraceEvent(TraceEventType.Information, "DataAccessProvider initialized");
                }
                catch (Exception exp)
                {
                    initErrorsCount++;
                    Trace.TraceEvent(TraceEventType.Error,"The DataAccessProvider initialization has thrown an exception of type \"{0}\". Details: {1}", exp.GetType(), exp.Message);

                    if (initErrorsCount == MAX_ERRORS)
                    {
                        Trace.TraceEvent(TraceEventType.Error, "Initialization errors count max limit reached. Closing application");
                        return;
                    }
                }

                if(dap == null)
                {
                    Trace.TraceEvent(TraceEventType.Information, "DataAccessProvider initialization retry in 1 minute");
                    Thread.Sleep(TimeSpan.FromMinutes(1));
                    continue;
                }

                initErrorsCount = 0;

                var worker = new KillmailWorker
                {
                    ApiServices = api,
                    PricesProvider = new EvePriceServicesProvider(),
                    DataAccessProvider = dap,
                    ItemPriceRefreshDelay = 3,
                    Trace = new TraceSource("KillmailWorker")
                };

                var kills = new List<IFeedKillmail>();

                Trace.TraceEvent(TraceEventType.Information, "Checking for killmails");

                // Loading Corporations and Characters API keys
                var keys = dap.FindAll<EveApiKeys>(false);
                
                if(keys!=null)
                    foreach (var eveApiKey in keys)
                    {
                        IEnumerable<IFeedKillmail> feedkills = null;
                        switch (eveApiKey.Type)
                        {
                            case EveApiKeys.KeyTypesEnum.Character:
                                feedkills = api.GetCharacterKillmails(eveApiKey.KeyId, eveApiKey.VerificationCode);
                                break;
                            case EveApiKeys.KeyTypesEnum.Corporation:
                                feedkills = api.GetCorporationKillmails(eveApiKey.KeyId, eveApiKey.VerificationCode);
                                break;
                        }
                        int count = feedkills != null ? feedkills.Count() : 0;
                        Trace.TraceEvent(TraceEventType.Information, "{0} killmails received from CCP API", count );
                        if (count > 0)
                            kills.AddRange(feedkills);
                    }

                // Loading Alliance killboard owners
                var alliances = dap.FindAll<KillboardParameter>(p => p.Key == KillboardParameter.KEY_ALLIANCE, false);

                using (var provider = new KillmailFeedProvider())
                    foreach (var alliance in alliances)
                    {
                        Trace.TraceEvent(TraceEventType.Information, "Retrieving killmails from Eve kill for Alliance Id:{0}", alliance.Value);

                        var temp = provider.GetKillmails(
                            int.Parse(alliance.Value), 
                            KillmailFeedProvider.IdTypesEnum.Alliance, 
                            Settings.Default.MaxKill);

                        if (temp != null)
                            kills.AddRange(temp);

                        Trace.TraceEvent(TraceEventType.Information, "{1} killmails received from Eve kill for Alliance Id:{0}", alliance.Value, temp != null ? temp.Count() : 0);
                    }
                
                if (kills.Any())
                {
                    Trace.TraceEvent(TraceEventType.Information, "Processing killmails");

                    var st = new Stopwatch();
                    st.Start();

                    int count = 0;
                    foreach (var km in kills.Where(k => k.CcpId > 0))
                    {
                        try
                        {
                            worker.SaveKillmail(km);
                            count++;
                        }
                        catch (Exception exp)
                        {
                            Trace.TraceEvent(TraceEventType.Error,exp.Message);
                        }
                    }

                    st.Stop();
                    Trace.TraceEvent(TraceEventType.Information, "{0} on {1} Killmails processed. Elapsed : {2}", count, kills.Count, st.Elapsed);

                    kills.Clear();
                    kills = null;
                }
                else
                {
                    Trace.TraceEvent(TraceEventType.Information, "No killmail to process");
                }

                worker = null;

                dap.Dispose();
                dap = null;
                
                GC.Collect();
                Thread.Sleep(TimeSpan.FromMinutes(15));
            }

            api.Dispose();
            api = null;
        }

    }

}
